﻿@page "/"
@using System.Diagnostics
@using System.Diagnostics.CodeAnalysis
@using System.Text.Json
@using System.IO
@using Microsoft.JSInterop
@using zy_simu.Data
@inject IJSRuntime JSRuntime
@inject DialogService DialogService
@inject SimuCfg emu_cfg
@inject DeviceSnap dev_snap
@inject MacroService macro_service
@inject BlazorWebViewReaction blazor_webview

<BootstrapBlazorRoot>
<div style="margin:20px">

    <div class="row">
        <div class="col-4">
            @if(dev_snap.disp_panel == 5)
            {
                <DisplayPanel326 @ref="DispPanel326"></DisplayPanel326> @*显示模拟*@
            }
            else if (dev_snap.disp_panel == 6)
            {
                <DisplayPanel1625 @ref="DispPanel1625"></DisplayPanel1625> @*显示模拟*@
            }
            else
            {
                <DisplayPanelGeneral @ref="DispPanelGen"></DisplayPanelGeneral> @*显示模拟*@
            }
            <Divider Text="模拟测试参数" />
            <HardwarePanel @ref="HWPanel"></HardwarePanel>  @*硬件模拟*@
        </div>
        <div class="col-4"> @*参数表和状态表*@
            <div class="row">
                <CtrlParameterTable @ref="param_table"></CtrlParameterTable>
            </div>
            <Divider />
            <div class="row">
                <CtrlStateTable @ref="state_table"></CtrlStateTable>
            </div>
        </div>
        <div class="col-4"> @*参数表, 启动/设置按钮 *@
            <MacroPanel @ref="macro_ex"></MacroPanel>   @*宏记录和执行器*@
            <div class="row" style="margin-top:10px; float:right;">
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="SimuCtrlSwitch"><i class="fas fa-play"> </i> @btn_power_txt</button>
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_emu_setting" disabled="@(btn_power_txt == "关闭模拟器")"> <i class="fas fa-gear"> </i> 配置模拟器 </button>
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_test1_click"> 测试和自检 </button>
                </div>
                <div class="col-auto">
                    @TestString
                </div>

            </div>
        </div>
    </div>
</div>
</BootstrapBlazorRoot>

@code {

    private double window_height;
    private double window_width;
    private DisplayPanel? DispPanel = default!;
    private DisplayPanelGeneral DispPanelGen = default!;
    private DisplayPanel326? DispPanel326 = default!;
    private DisplayPanel1625 DispPanel1625 = default!;
    [AllowNull] private HardwarePanel HWPanel;
    [AllowNull] private CtrlParameterTable param_table;
    [AllowNull] private CtrlStateTable state_table;
    // private DeviceSnap? dev_snap = null;
    private MacroPanel macro_ex = default!;


    protected override void OnInitialized()
    {
        DispPanel = DispPanelGen;
        base.OnInitialized();
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) // 根据页面大小匹配控件size
        {
            window_height = await JSRuntime.InvokeAsync<double>("JsGetWindowHeight");
            param_table.SetHeight((int)(window_height - 135) / 5 * 2);
            state_table.SetHeight((int)(window_height - 135) / 5 * 3);
            StateHasChanged();
        }
    }
    private System.Timers.Timer? timer = null;
    private byte last_ctrl_mode = 0xff;
    private void timer_50ms_cb(object? sender, System.Timers.ElapsedEventArgs e)
    {
        if (timer == null) return;
        timer.Stop();   // 暂停，防止多线程重入

        // 对本轮操作计时
        System.DateTime start = System.DateTime.Now;
        if (dev_snap == null) goto timer_50ms_cb_reload_timer;
        // 读取并且设置是否人为修改参数表和状态表
        dev_snap.ChangePmTable(param_table.modified_idx, param_table.modified_value);
        dev_snap.ChangeStTable(state_table.modified_idx, state_table.modified_value);
        param_table.modified_idx = state_table.modified_idx = -1;
        // 读取并且设置key变化
        dev_snap.ChangeKey(DispPanel.GetKey());
        // 模拟器仿真硬件变化 - 更新模拟硬件变化
        HWPanel.UpdateSimuData(dev_snap);

        // 宏操作
        macro_ex.Refresh();

        // dev_snap.QuerySnapshot(false);  TODO 逻辑简化
        if (dev_snap.st.ctrl_mode != last_ctrl_mode)
        {
            dev_snap.ExchangeWithDev(true);
            param_table.ChangeTable();
            last_ctrl_mode = dev_snap.st.ctrl_mode;
        }
        else 
        {
            dev_snap.ExchangeWithDev(false);
        }
        dev_snap.Recv();

        // 掉电, 关机
        if (!emu_cfg.pow && !emu_cfg.battery){
            SimuCtrlPowerOff();
            InvokeAsync(StateHasChanged);
            goto timer_50ms_cb_reload_timer;
        }

        // 启动/关闭cat1
        if (HWPanel.GetCat1Status(dev_snap)) dev_snap.Cat1PowerOn();
        else dev_snap.Cat1PowerOff();

        // 更新显示变化
        DispPanel.Display(dev_snap.disp_hw_buf, dev_snap.k_state);
        param_table.UpdateData(dev_snap.pms_tb);    // 更新参数表
        state_table.UpdateData(dev_snap.st);     // 更新状态表


timer_50ms_cb_reload_timer:
        double interval = (System.DateTime.Now - start).TotalMilliseconds;
        timer.Interval = (interval < 50) ? (50 - interval) : 50;
        // timer.Interval = (interval < 100) ? (100 - interval) : 100;
        timer.Start();
    }

    // 启动/关闭模拟器
    public async Task<bool> SimuCtrlPowerOn()
    {
        // 安装停止函数, 供blazor外部强制停止时调用。
        blazor_webview.Close = SimuCtrlPowerOff;
        // 判断是否要清除flash，相当于恢复出厂设置
        if (emu_cfg.factory_reset)
            File.Delete(@".\app\zy_m0_eeprom.dat");
        // 启动硬件模拟
        HWPanel.Start();
        // 设置定时器
        timer = new System.Timers.Timer(dev_snap.TASK_PERIOD);
        timer.AutoReset = false;
        timer.Elapsed += timer_50ms_cb;
        // 启动仿真设备快照
        if (await dev_snap.Start(emu_cfg) == false) 
            return false;
        StateHasChanged();
        // await InvokeAsync(StateHasChanged);
        // 重新根据设备型号安装合适的display panel
        if (dev_snap.disp_panel == 5) DispPanel = DispPanel326;
        else if (dev_snap.disp_panel == 6) DispPanel = DispPanel1625;
        else DispPanel = DispPanelGen;
        DispPanel.Init();
        // macro_service.DispPanel = DispPanel;
        timer.Start();
        return true;
    }
    public async Task SimuCtrlPowerOff()
    {
        KgConsoleManager.Hide();
        if (timer != null)
        {
            timer.Elapsed -= timer_50ms_cb;
            timer.Stop();
            System.Threading.Thread.Sleep(20);
            timer = null;
        }
        await dev_snap.Stop();
        blazor_webview!.get_webview().Reload();
        blazor_webview!.Close = null;
    }
    private string btn_power_txt = "启动模拟器";
    public async Task SimuCtrlSwitch()
    {
        if (btn_power_txt == "启动模拟器")
        {
            System.Console.WriteLine("---------- Simulator Running ----------");
            if (await SimuCtrlPowerOn() == false) return;
            macro_service.Init(dev_snap, DispPanel!, HWPanel, emu_cfg);
            btn_power_txt = "关闭模拟器";
        }
        else
        {
            System.Console.WriteLine("---------- Simulator Closing ----------");
            await SimuCtrlPowerOff();
            btn_power_txt = "启动模拟器";
        }
    }

    private void btn_emu_setting()
    {
        var option = new DialogOption()
        {
            Title = "仿真器配置",
            ShowFooter = false,
            Size = Size.Medium,
        };
        // 传递option给内部模板，这样内部可以call option.CloseDialogAsync() 来主动关闭对话框
        option.Component = BootstrapDynamicComponent.CreateComponent<SimuCfgModeDialog>(new Dictionary<string, object?>
        {
            [nameof(SimuCfgModeDialog.option)] = option,
        });
        DialogService.Show(option);
    }

    private string TestString = "";
    private void btn_test1_click()
    {
        DialogService.Show(new DialogOption()
        {
            Title = "BLE 设备选择",
            Component = BootstrapDynamicComponent.CreateComponent<BleConfigDialog>(),
            Size = Size.Large,
        });
    }
}
